#ifndef __GLF_CORE_EVENT_H_INCLUDED__
#define __GLF_CORE_EVENT_H_INCLUDED__

#include <glf/core/bytearray.h>
#include <glf/core/mutex.h>
#include <glf/core/spinLock.h>

#include <glf/io/stream.h>

#include <list>
#include <map>
#include <queue>
#include <string>
#include <vector>
#include <memory>
#include <sstream>


namespace glf {

	namespace debugger {
		class PacketReader;
		class PacketWriter;
	}

	static const int APP_EVENT_TYPE_BASE		= 100;
	static const int INPUT_EVENT_TYPE_BASE		= 200;
	static const int USER_EVENT_TYPE_BASE		= 1000;

	class AppEventSerializer;
	class EventManager;
	class EventSerializer;
	class Macro;

	namespace remote
	{
		class Controller;
	}

	const char* GetEventName(int evtId);



	//CoreEvent
	struct CoreEvent {
		
		friend class EventSerializer;
		friend class EventManager;
		friend class remote::Controller;

	public:

		//FlagBits
		enum FlagBits
		{
			FB_EXTERNAL	= 1<<0,
			FB_POSTED	= 1<<1
		};

	public:
		//IMPORTANT: Every derived structure should not be bigger than MAX_SIZE.
		static const size_t MAX_SIZE = 128;
		typedef struct { char data[MAX_SIZE]; } DataType;

	public:
		CoreEvent(int type);
		//IMPORTANT: Do not add destructor here or in any derived structures because
		//           they will never be called. For efficiency, events are internally 
		//           copied as byte arrays of MAX_SIZE, hence all C++ mechanims are broken.
		//			 A corollary is that all stucts derived from CoreEvent can only hold
		//           simple types (char, int, float, char *, ...). However, you can use 
		//           cascaded constructors to initialize data.

	public:
		bool IsExternal() const;
		bool IsPosted() const;
		
	public:		
		ushort mType;

	private:
		void MarkAsExternal();
		void MarkAsPosted();
		
	private:
		ushort mFlags;

	private:
		// Dynamic allocation is prevented
		//
		// Using a "bodyless" method will output a linking error only if the CoreEvent is
		// dynamically allocated.
		static void* please_read_the_comments_in_event_dot_h();

		void* operator new   (size_t) throw() { return please_read_the_comments_in_event_dot_h(); }
		void* operator new[] (size_t) throw() { return please_read_the_comments_in_event_dot_h(); }
		void  operator delete   (void*) throw() {}
		void  operator delete[] (void*) throw() {}
	};

	//Event
	inline CoreEvent::CoreEvent(int type) : 
		mType((ushort)type),
		mFlags(0)		
	{
	}

	inline bool CoreEvent::IsExternal() const
	{
		return (mFlags & FB_EXTERNAL) != 0;
	}

	inline bool CoreEvent::IsPosted() const
	{
		return (mFlags & FB_POSTED) != 0;
	}

	inline void CoreEvent::MarkAsExternal()
	{
		mFlags |= FB_EXTERNAL;
	}

	inline void CoreEvent::MarkAsPosted()
	{
		mFlags |= FB_POSTED;
	}

	//EventReceiver 
	class EventReceiver {
	public:
		EventReceiver() : mEnabled(true) {}
		virtual ~EventReceiver() {}

	public:
		virtual bool OnEvent(const CoreEvent &evt) = 0;

	public:
		bool IsEnabled() const { return mEnabled; }
		void SetEnable(bool enabled) { mEnabled = enabled; }	

	private:
		bool mEnabled;
	};

	//EventDataReader
	typedef ByteReader EventDataReader;

	//EventDataWriter
	typedef ByteWriter EventDataWriter;

	//EventSerializer
	class EventSerializer {
	public:
		virtual ~EventSerializer() {}
	
	public:
		const ushort &GetEventFlags(const glf::CoreEvent &coreEvent) const;
		ushort &GetEventFlags(glf::CoreEvent &coreEvent) const;

	public:
		virtual bool Serialize(EventDataWriter &writer, const glf::CoreEvent &event) const = 0;
		virtual glf::CoreEvent *Unserialize(glf::CoreEvent::DataType &data, EventDataReader &reader) const = 0;
	};

	//EventManager
	class EventManager {	
	public:
		
		//Priority
		enum Priority
		{
			EP_LOW		= 100,
			EP_NORMAL	= 200,
			EP_HIGH		= 300		
		};				

	public:
		EventManager();
		virtual ~EventManager();

	public: //Event registration		
		std::string GetEventName(int type);
		EventSerializer *GetEventSerializer(int type);
		size_t GetEventSize(int type);
		int GetEventType(const char *eventName);				
		void RegisterEventSerializer(std::vector<int> types, EventSerializer *eventSerializer);
		template <typename EVENT_STRUCT>		
		void RegisterFixedEventType(int type, const char *eventName = 0);		
		template <typename EVENT_STRUCT>
		int RegisterUserEventType(int &type, const char *eventName);		

		void RegisterMacro(Macro* macro) {
			mMacros.push_back(macro);
		}
		void UnregisterMacro(Macro* macro) {
			for(std::vector<Macro*>::iterator it = mMacros.begin(); it != mMacros.end(); )
			{
				if(*it == macro)
					it = mMacros.erase(it);
				else
					++it;
			}
		}

	public: //Receiver registration
		void AddEventReceiver(
			EventReceiver* evtReceiver, 
			int priority = EP_NORMAL);
		
		void AddEventReceiver(
			EventReceiver* evtReceiver, 
			int priority,
			std::vector<int>& allowedEventTypes);
		
		bool HasEventReceiver() const;		
		void RemoveEventReceiver(EventReceiver* evtReceiver);

	public: //Event post/send
		
		//! Dispatch all queued events
		void DispatchEvents();

		//! Post an event to all event receivers.
		/** Posted events are queued and then processed when DispatchEvents is called
		\param event Event to post.
		*/
		void PostEvent(const glf::CoreEvent &event);

		//! Send an event to all event receivers.
		/** Sended events are processed immediatly.
		\param event Event to send.
		\return True is the event has been absorbed by one receiver.
		*/
		bool SendEvent(const glf::CoreEvent &event);		

	protected:
		//! Update event just before is really sended
		/**
		\param event Event to update.
		\return False if the event must be ignored (not sended).
		*/
		virtual bool PreSendEvent(CoreEvent &evt);

	private:

		//TypeInfo
		struct TypeInfo
		{
			TypeInfo() : mSerializer(0), mSize(0) {}
			std::string mName;
			EventSerializer *mSerializer;
			size_t mSize;
			// Intenal id used by bit array of allowed events
			int mId;
		};

	private:		
		void RegisterFixedEventType(int type, size_t size, const char *eventName);		
		int RegisterUserEventType(int &type, const char *eventName, size_t size);

	private:

		//! EventReceiverData
		struct EventReceiverData
		{
			//! Use of std::vector<bool> template specialization 
			//! where each element occupies only one bit
			typedef std::vector<bool> BitArray;

			//! pointer to the receiver
			EventReceiver* mRcv;			

			//! event handling priority
			int mPriotity;

			//! creation order. Used by operator< to sort events with the
			//! same priority
			int mOrder;

			//! array of accepted events (empty if all events are allowed)
			BitArray mAllowedEvents;

			bool IsEventAllowed(int eventIndex) const
			{
				return 
					// No filter
					mAllowedEvents.empty() || 
					// or allowed
					(eventIndex >= 0 && 
					eventIndex < (int)mAllowedEvents.size() && 
					mAllowedEvents[eventIndex]);
			}

			bool operator<(const EventReceiverData &other) const
			{
				// For same priority, we use creation order because, and according to STL,
				// "elements that would compare equal to each other are not guaranteed 
				// to keep their original relative order."
				return (mPriotity == other.mPriotity) ? (mOrder < other.mOrder) : (mPriotity > other.mPriotity);
			}

			//! NOTE: I don't understand why this operator is needed... but it's needed and never used
			bool operator==(const EventReceiverData &other) const
			{
				return false;
			}
		};

		typedef std::list<EventReceiverData> EventReceiverDataList;		

	private:
		bool RaiseEvent(CoreEvent &evt);

	private:
		//!
		AppEventSerializer *mAppEventSerializer;

		//!
		std::queue<CoreEvent::DataType> mEventQueue;

		//!
		std::map<std::string, int> mEventTypes;

		//!
		std::map<int, TypeInfo> mEventInfos;

		//!
		EventReceiverDataList mEventReceivers;

		SpinLock mSpinLock;

		//! number of active receiver
		int mReceiverCount;

		//! this is used to generate a unique "order" number for each created
		//! event receiver.
		int mReceiverOrder;

		//!
		int mUserEventType;

		std::vector<Macro*> mMacros;
	};

	//EventReceiver
	template <typename EVENT_STRUCT>
	void EventManager::RegisterFixedEventType(int type, const char *eventName)
	{
		RegisterFixedEventType(type, sizeof(EVENT_STRUCT), eventName);
	}
	template <typename EVENT_STRUCT>
	int EventManager::RegisterUserEventType(int &type, const char *eventName)
	{
		return RegisterUserEventType(type, eventName, sizeof(EVENT_STRUCT));
	}

	class Macro 
		:	private EventReceiver
		,	private NonCopyable
	{
	public:
		typedef std::vector<int> EventsToRecord;
		enum EventType {
			EET_PLAYBACKSTARTED,
			EET_PLAYBACKPAUSED,
			EET_PLAYBACKUNPAUSED,
			EET_PLAYBACKSTOPPED,
			EET_PLAYBACKENDED,
			EET_RECORDINGSTARTED,
			EET_RECORDINGFINISHED,
		};

		typedef void (*FnCallback)(Macro* macro, EventType et, void* param, void* ud);

		struct EventCallback {
			FnCallback callback;
			void* userData;
		};
		typedef std::vector<EventCallback> EventCallbacks;

		enum Mode {
			EM_DISABLED,
			EM_RECORDING,
			EM_PLAYING,
			EM_PAUSED,
		};
		
		Macro(EventManager& evtMgr, const std::string& filename, bool isLocal=true, ios::openflag loc = ios::loc_home);
		Macro(EventManager& evtMgr, debugger::PacketReader& in);
		~Macro();
		
		void SetEventToRecord(int evt) {
			mEventsToRecord.clear();
			mEventsToRecord.push_back(evt);
		}
		void SetEventsToRecord(const EventsToRecord& evtToRecord) {
			mEventsToRecord = evtToRecord;
		}

		void ClearEvents() {
			mEventsToRecord.clear();
		}
		
		void AddEventToRecord(int evt) {
			mEventsToRecord.push_back(evt);
		}
		void AddEventsToRecord(int evtStart, int evtEnd) {
			while(evtStart < evtEnd)
				mEventsToRecord.push_back(evtStart++);
		}
		void AddEventsToRecord(const EventsToRecord& evtToRecord) {
			mEventsToRecord.insert(mEventsToRecord.end(), evtToRecord.begin(), evtToRecord.end());
		}

		void UpdateFrame();

		bool IsDisabled() const {
			return mMode == EM_DISABLED;
		}

		void StartRecording();
		bool IsRecording() const {
			return mMode == EM_RECORDING;
		}
		void StopRecording();
		
		void StartPlaying();
		bool IsPlaying() const {
			return mMode == EM_PLAYING;
		}
		void Pause();
		bool IsPaused() const {
			return mMode == EM_PAUSED;
		}
		int GetProgress() const {
			return mFrame;
		}
		int GetDuration() const {
			return mTotalFrames;
		}

		void StopPlaying();

		void Clear() {
			mWriter.Clear();
		}
		int CountDuration();

		void SetData(const char* buf, int length);
		
		void Load(const char* filename, ios::openflag flag);
		void Load(debugger::PacketReader& in);

		void Save();
		void Save(const char* filename, ios::openflag flag);
		void Save(debugger::PacketWriter& out);

		bool IsLocal() const {
			return mIsLocal;
		}
		
		void AddCallback(FnCallback fn, void* ud) {
			EventCallback ec = { fn, ud };
			mEventCallbacks.push_back(ec);
		}
		
		void BroadcastEvent(EventType et, void* param) {
			for(EventCallbacks::const_iterator it = mEventCallbacks.begin(); it != mEventCallbacks.end(); ++it) {
				const EventCallback& ec = *it;
				(ec.callback)(this, et, param, ec.userData);
			}
		}
	private:
		bool OnEvent(const CoreEvent& evt);

		EventManager& mEvtMgr;

		bool mIsLocal;
		stringc mFilename;
		ios::openflag mLocation;

		std::stringstream mStream;
		ByteWriter mWriter;
		std::auto_ptr<ByteReader> mReader;
		int mFrame;
		int mTotalFrames;

		EventsToRecord mEventsToRecord;
		Mode mMode;

		int mFramesWithoutEvent;
		int mEventsThisFrame;


		
		EventCallbacks mEventCallbacks;
	};
}

#endif //__GLF_CORE_EVENT_H_INCLUDED__
